﻿using System;
using System.IO;
using System.Custom;
using System.Drawing;
using System.Custom.Web;
using System.Globalization;
using System.Windows.Forms;
using System.Custom.Window;
using System.Custom.Drawing;
using MainModule.Properties;
using System.Collections.Generic;

namespace MainModule
{
   public partial class CssEditWindow : Window
   {
      string FCss = "";
      bool FParsingStyle;
      string FLogStyleName;
      InternetCommunicator FCommunicator = InternetCommunicator.Self;

      public CssEditWindow()
      {
         InitializeComponent();

         Css = FCommunicator.SelectedLogStyle;
         FLogStyleName = Settings.Default.SelectedLogStyleName;
         Text = Text.Replace("<file>", FLogStyleName);
      }

      protected override void Dispose(bool disposing)
      {       
         if (disposing && (components != null))
         {
            components.Dispose();
         }
         base.Dispose(disposing);
      }

      public string Css
      {
         get
         {
            return FCss;
         }
         private set
         {
            if (ParseStyle(value))
            {
               FCss = value;

               if (!Text.EndsWith("*")) Text += "*";

               if (CssChanged != null) CssChanged(this, new CssChangedEventArgs(FLogStyleName, true));
            }
         }
      }

      public event EventHandler<CssChangedEventArgs> CssChanged;

      private void ApplyStyle()
      {
         Css = string.Format(Resources.LogStyleTemplate,
               buttonFont.Font.SizeInPoints + "pt",
               buttonFont.Font.FontFamily.Name,
               ColorTranslator.ToHtml(panelBgColor.BackColor),
               textBoxImagePath.Text != "" ? "url(" + Shell.GetShortPath(textBoxImagePath.Text) + ")" : "",
               (comboBoxImagePosition.SelectedItem.ToString() == "Center" ? "No-repeat" : comboBoxImagePosition.SelectedItem.ToString()),
               (comboBoxImagePosition.SelectedItem.ToString() == "Center" ? "Center" : "Top Left"),
               "scroll",// "fixed" the same as position:expand
               ColorTranslator.ToHtml(panelCaptionIncomingColor1.BackColor) + " " +
               ColorTranslator.ToHtml(panelCaptionIncomingColor1.BackColor) + " " +
               ColorTranslator.ToHtml(panelCaptionIncomingColor2.BackColor) + " " +
               ColorTranslator.ToHtml(panelCaptionIncomingColor2.BackColor),
               ColorTranslator.ToHtml(panelCaptionOutgoingColor1.BackColor) + " " +
               ColorTranslator.ToHtml(panelCaptionOutgoingColor1.BackColor) + " " +
               ColorTranslator.ToHtml(panelCaptionOutgoingColor2.BackColor) + " " +
               ColorTranslator.ToHtml(panelCaptionOutgoingColor2.BackColor),
               "bold", /* nick font-weight */
               ColorTranslator.ToHtml(panelNickIncomingColor.BackColor),
               ColorTranslator.ToHtml(panelNickOutgoingColor.BackColor),
               ColorTranslator.ToHtml(panelDateIncomingColor.BackColor),
               ColorTranslator.ToHtml(panelDateOutgoingColor.BackColor),
               numericBordersRadius.Value,
               numericBordersRadius.Value,
               numericBordersWidth.Value,
               ColorTranslator.ToHtml(panelBordersIncomingColor.BackColor),
               ColorTranslator.ToHtml(panelContentIncomingColor1.BackColor) + " " +
               ColorTranslator.ToHtml(panelContentIncomingColor1.BackColor) + " " +
               ColorTranslator.ToHtml(panelContentIncomingColor2.BackColor) + " " +
               ColorTranslator.ToHtml(panelContentIncomingColor2.BackColor),
               ColorTranslator.ToHtml(panelBordersOutgoingColor.BackColor),
               ColorTranslator.ToHtml(panelContentOutgoingColor1.BackColor) + " " +
               ColorTranslator.ToHtml(panelContentOutgoingColor1.BackColor) + " " +
               ColorTranslator.ToHtml(panelContentOutgoingColor2.BackColor) + " " +
               ColorTranslator.ToHtml(panelContentOutgoingColor2.BackColor),
               numericContentMargin.Value,
               "silver", /* ts font-color */
               ColorTranslator.ToHtml(panelTextColor.BackColor),
               numericMessagePadding.Value, /* reflection padding */
               numericReflection.Value > 0 ? "" : "!",
               (numericReflection.Value / 100).ToString("G", CultureInfo.InvariantCulture),
               FCommunicator.CurrentAccount.CustomName,
               FCommunicator.CurrentAccount.CustomName.ToLower() + "@somewhere") + Resources.CommonLogStyle;
      }
      private bool ParseStyle(string s)
      {
         FParsingStyle = true;

         try
         {
            CssReader css = new CssReader(s);

            string attr = css["body", "font-family"];
            if (attr != null) buttonFont.Font = new Font(attr, 10);

            attr = css["body", "font-size"];
            if (attr != null) buttonFont.Font = new Font(buttonFont.Font.FontFamily.Name, float.Parse(attr.Replace("pt", "")), GraphicsUnit.Point);

            buttonFont.Text = buttonFont.Font.FontFamily.Name + ", " + buttonFont.Font.SizeInPoints + "pt";

            attr = css["body", "background-color"];
            if (attr == null) attr = css["body", "background"];
            if (attr != null) panelBgColor.BackColor = GetColor(0, attr);

            attr = css["body", "background-image"];
            if (attr != null)
            {
               attr = attr.SubstrAfter("url(").SubstrBefore(")");
               textBoxImagePath.Text = File.Exists(attr) ? attr : "";
            }

            attr = css["body", "background-repeat"];
            if (attr != null) comboBoxImagePosition.SelectedItem = attr;

            attr = css["body", "background-position"];
            if (attr != null && attr == "Center") comboBoxImagePosition.SelectedItem = "Center";

            attr = css[".refl", "-reflection-opacity-start"];
            if (attr != null) numericReflection.Value = (decimal)(float.Parse(attr, CultureInfo.InvariantCulture) * 100);

            attr = css[".refl", "padding"];
            if (attr != null)
            {
               string[] paddings = attr.Replace("px", "").Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
               numericMessagePadding.Value = decimal.Parse(paddings[2]);
            }

            attr = css[".message.in", "background"];
            if (attr == null) attr = css[".message.in", "background-color"];
            if (attr != null)
            {
               panelContentIncomingColor1.BackColor = GetColor(0, attr);
               panelContentIncomingColor2.BackColor = GetColor(2, attr);
            }

            attr = css[".message.out", "background"];
            if (attr == null) attr = css[".message.out", "background-color"];
            if (attr != null)
            {
               panelContentOutgoingColor1.BackColor = GetColor(0, attr);
               panelContentOutgoingColor2.BackColor = GetColor(2, attr);
            }

            attr = css[".caption.in", "background"];
            if (attr == null) attr = css[".caption.in", "background-color"];
            if (attr != null)
            {
               panelCaptionIncomingColor1.BackColor = GetColor(0, attr);
               panelCaptionIncomingColor2.BackColor = GetColor(2, attr);
            }

            attr = css[".caption.out", "background"];
            if (attr == null) attr = css[".caption.out", "background-color"];
            if (attr != null)
            {
               panelCaptionOutgoingColor1.BackColor = GetColor(0, attr);
               panelCaptionOutgoingColor2.BackColor = GetColor(2, attr);
            }

            attr = css[".message", "border-radius"];
            if (attr != null) numericBordersRadius.Value = decimal.Parse(attr.SubstrBefore("px"));

            attr = css[".message.out", "border"];
            if (attr != null) panelBordersOutgoingColor.BackColor = GetColor(2, attr);

            attr = css[".message.in", "border"];
            if (attr != null)
            {
               string[] options = attr.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

               numericBordersWidth.Value = decimal.Parse(options[0].SubstrBefore("px"));
               panelBordersIncomingColor.BackColor = GetColor(0, options[2]);
            }

            attr = css[".nick.in", "color"];
            if (attr != null) panelNickIncomingColor.BackColor = GetColor(0, attr);

            attr = css[".nick.out", "color"];
            if (attr != null) panelNickOutgoingColor.BackColor = GetColor(0, attr);

            attr = css[".date.in", "color"];
            if (attr != null) panelDateIncomingColor.BackColor = GetColor(0, attr);

            attr = css[".date.out", "color"];
            if (attr != null) panelDateOutgoingColor.BackColor = GetColor(0, attr);

            attr = css[".text", "color"];
            if (attr != null) panelTextColor.BackColor = GetColor(0, attr);

            attr = css[".content", "padding"];
            if (attr == null) attr = css[".content", "margin"];
            if (attr != null) numericContentMargin.Value = decimal.Parse(attr);

            textBoxCss.Text = s;
            FParsingStyle = false;
            labelParserState.Visible = false;

            return true;
         }
         catch
         {
            ParseStyle(FCss); // return to current style which is parsable I hope

            FParsingStyle = false;
            labelParserState.Visible = true;
            DelayedAction.Do(labelParserState, () => labelParserState.Visible = false, 4000, true);
            return false;
         }
      }
      private Color GetColor(int index, string colors)
      {
         string[] colorArr = colors.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

         if (index > colorArr.Length) index = colorArr.Length - 1;

         try
         {
            return ColorTranslator.FromHtml(colorArr[index]);
         }
         catch
         {            
            return Color.White;
         }
      }
      private DialogResult ShowColorDialog(Color color)
      {
         colorDialog.Color = color;

         return colorDialog.ShowDialog();
      }

      private void buttonOk_Click(object sender, EventArgs e)
      {
         if (Text.EndsWith("*")) FCommunicator.SaveSettings(false);

         Close();
      }
      private void buttonSave_Click(object sender, EventArgs e)
      {
         if (saveFileDialog.ShowDialog() == DialogResult.OK)
         {
            System.IO.File.WriteAllText(saveFileDialog.FileName, Css);
         }
      }
      private void buttonLoad_Click(object sender, EventArgs e)
      {
         List<string> files = Shell.OpenFileDialog(Resources.S_Select_file, "", "CSS|*.css");

         if (files.Count > 0 && files[0].Length > 0)
         {
            Text = "CSS Editor - " + files[0];

            Css = File.ReadAllText(files[0]);
         }
      }
      private void buttonFont_Click(object sender, EventArgs e)
      {
         fontDialog.Font = buttonFont.Font;

         if (fontDialog.ShowDialog() == DialogResult.OK)
         {
            buttonFont.Font = fontDialog.Font;
            buttonFont.Text = buttonFont.Font.FontFamily.Name + ", " + buttonFont.Font.SizeInPoints + "pt";

            ApplyStyle();
         }
      }
      private void buttonCancel_Click(object sender, EventArgs e)
      {
         if (CssChanged != null) CssChanged(this, new CssChangedEventArgs(FLogStyleName, false));

         Close();
      }
      private void numeric_ValueChanged(object sender, EventArgs e)
      {
         if (FParsingStyle) return;

         ApplyStyle();
      }
      private void textBoxCss_TextChanged(object sender, EventArgs e)
      {
         if (FParsingStyle) return;

         DelayedAction.Do(this, () =>
         {
            Css = textBoxCss.Text;
         },
         600, true);
      }
      private void buttonSelectImage_Click(object sender, EventArgs e)
      {
         List<string> files = Shell.OpenFileDialog(Resources.S_Select_file, "", "PNG;JPEG;JPG;GIF;WMF|*.PNG;*.JPEG;*.JPG;*.GIF;*.WMF|*.*|*.*");

         if (files.Count > 0 && files[0].Length > 0)
         {
            if (comboBoxImagePosition.SelectedIndex < 0) comboBoxImagePosition.SelectedIndex = 0;

            textBoxImagePath.Text = files[0];
         }
      }
      private void panelColor_MouseClick(object sender, MouseEventArgs e)
      {
         Panel panel = sender as Panel;

         if (ShowColorDialog(panel.BackColor) == DialogResult.OK)
         {
            panel.BackColor = colorDialog.Color;

            ApplyStyle();
         }
      }
      private void textBoxImagePath_TextChanged(object sender, EventArgs e)
      {
         if (FParsingStyle) return;

         DelayedAction.Do(this, () =>
         {
            if (textBoxImagePath.Text == "" || File.Exists(textBoxImagePath.Text)) ApplyStyle();
         },
         600, true);
      }
      private void panelBgColor_MouseClick(object sender, MouseEventArgs e)
      {
         if (ShowColorDialog((sender as Control).BackColor) == DialogResult.OK)
         {
            panelBgColor.BackColor = colorDialog.Color;
            ApplyStyle();
         }
      }
      private void panelBordersColor_MouseClick(object sender, MouseEventArgs e)
      {
         Panel panel = sender as Panel;

         if (e.Button == MouseButtons.Right)
         {
            if (sender == panelBordersOutgoingColor)
            {
               panelBordersOutgoingColor.BackColor = panelBordersIncomingColor.BackColor;

               ApplyStyle();
            }
         }
         else
         {
            if (ShowColorDialog(panel.BackColor) == DialogResult.OK)
            {
               panel.BackColor = colorDialog.Color;

               ApplyStyle();
            }
         }
      }
      private void panelBodyIncomingColor_MouseClick(object sender, MouseEventArgs e)
      {
         if (e.Button == MouseButtons.Right)
         {
            panelContentIncomingColor2.BackColor = panelContentIncomingColor1.BackColor;

            ApplyStyle();
         }
         else
         {
            if (ShowColorDialog((sender as Control).BackColor) == DialogResult.OK)
            {
               if (sender == panelContentIncomingColor2)
               {
                  panelContentIncomingColor2.BackColor = colorDialog.Color;
               }
               else
               {
                  panelContentIncomingColor1.BackColor = colorDialog.Color;
                  HSLColor c = new HSLColor(panelContentIncomingColor1.BackColor);
                  c.Luminosity -= 25;
                  panelContentIncomingColor2.BackColor = c;
               }
               ApplyStyle();
            }
         }
      }
      private void panelBodyOutgoingColor_MouseClick(object sender, MouseEventArgs e)
      {
         if (e.Button == MouseButtons.Right)
         {
            panelContentOutgoingColor2.BackColor = panelContentOutgoingColor1.BackColor;

            ApplyStyle();
         }
         else
         {
            if (ShowColorDialog((sender as Control).BackColor) == DialogResult.OK)
            {
               if (sender == panelContentOutgoingColor2)
               {
                  panelContentOutgoingColor2.BackColor = colorDialog.Color;
               }
               else
               {
                  panelContentOutgoingColor1.BackColor = colorDialog.Color;
                  HSLColor c = new HSLColor(panelContentOutgoingColor1.BackColor);
                  c.Luminosity -= 25;
                  panelContentOutgoingColor2.BackColor = c;
               }
               ApplyStyle();
            }
         }
      }
      private void panelCaptionIncomingColor_MouseClick(object sender, MouseEventArgs e)
      {
         if (e.Button == MouseButtons.Right)
         {
            panelCaptionIncomingColor2.BackColor = panelCaptionIncomingColor1.BackColor;

            ApplyStyle();
         }
         else
         {
            if (ShowColorDialog((sender as Control).BackColor) == DialogResult.OK)
            {
               if (sender == panelCaptionIncomingColor2)
               {
                  panelCaptionIncomingColor2.BackColor = colorDialog.Color;
                  panelDateIncomingColor.BackColor = colorDialog.Color;
               }
               else
               {
                  panelCaptionIncomingColor1.BackColor = colorDialog.Color;
                  HSLColor c = new HSLColor(panelCaptionIncomingColor1.BackColor);
                  c.Luminosity -= 25;
                  panelCaptionIncomingColor2.BackColor = c;
               }
               ApplyStyle();
            }
         }
      }
      private void panelCaptionOutgoingColor_MouseClick(object sender, MouseEventArgs e)
      {
         if (e.Button == MouseButtons.Right)
         {
            panelCaptionOutgoingColor2.BackColor = panelCaptionOutgoingColor1.BackColor;

            ApplyStyle();
         }
         else
         {
            if (ShowColorDialog((sender as Control).BackColor) == DialogResult.OK)
            {
               if (sender == panelCaptionOutgoingColor2)
               {
                  panelCaptionOutgoingColor2.BackColor = colorDialog.Color;
                  panelDateOutgoingColor.BackColor = colorDialog.Color;
               }
               else
               {
                  panelCaptionOutgoingColor1.BackColor = colorDialog.Color;
                  HSLColor c = new HSLColor(panelCaptionOutgoingColor1.BackColor);
                  c.Luminosity -= 25;
                  panelCaptionOutgoingColor2.BackColor = c;
               }
               ApplyStyle();
            }
         }
      }
      private void comboBoxImagePosition_SelectedIndexChanged(object sender, EventArgs e)
      {
         if (FParsingStyle) return;

         ApplyStyle();
      }
   }

   public class CssChangedEventArgs : EventArgs
   {
      public readonly bool Changed;

      public readonly string LogStyleName;

      public CssChangedEventArgs(string logStyleName, bool changed)
      {
         Changed = changed;
         LogStyleName = logStyleName;
      }
   }
}
